package com.deductive.web.disposition.sys;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.deductive.common.config.RuoYiConfig;
import com.deductive.common.core.controller.BaseController;
import com.deductive.common.core.domain.AjaxResult;
import com.deductive.common.core.page.TableDataInfo;
import com.deductive.common.utils.encrypt.MD5Util;
import com.deductive.domain.sys.SysFiles;
import com.deductive.service.sys.SysFilesService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.UUID;

import com.deductive.common.utils.file.FileUtils;


@RestController
@RequestMapping("/sysFiles")
@Api(tags = "文件管理", description = "文件上传、下载、查询、删除等文件管理相关接口")
public class SysFilesController extends BaseController {

    @Resource
    private SysFilesService sysFilesService;

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @GetMapping("/pageQuery")
    @ApiOperation(value = "分页查询文件", notes = "根据条件分页查询文件列表，支持按文件名、存储名、MIME类型、扩展名、状态等条件筛选")
    public TableDataInfo selectAll(
            @ApiParam(value = "查询条件", required = false)
            SysFiles sysFiles) {
        startPage();
        LambdaQueryWrapper<SysFiles> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(sysFiles.getFileName() != null, SysFiles::getFileName, sysFiles.getFileName());
        queryWrapper.like(sysFiles.getStorageName() != null, SysFiles::getStorageName, sysFiles.getStorageName());
        queryWrapper.like(sysFiles.getMimeType() != null, SysFiles::getMimeType, sysFiles.getMimeType());
        queryWrapper.like(sysFiles.getExtension() != null, SysFiles::getExtension, sysFiles.getExtension());
        queryWrapper.eq(sysFiles.getStatus() != null, SysFiles::getStatus, sysFiles.getStatus());
        queryWrapper.eq(sysFiles.getId() != null, SysFiles::getId, sysFiles.getId());
        List<SysFiles> list = this.sysFilesService.list(queryWrapper);
        return getDataTable(list);
    }

    @GetMapping("{id}")
    @ApiOperation(value = "根据ID查询文件", notes = "根据文件ID获取文件详细信息")
    public AjaxResult selectOne(
            @ApiParam(value = "文件ID", required = true, example = "1")
            @PathVariable Integer id) {
        return success(this.sysFilesService.getById(id));
    }


    @PutMapping
    @ApiOperation(value = "修改文件信息", notes = "更新文件的基本信息，如文件名、状态等")
    public AjaxResult update(
            @ApiParam(value = "文件信息对象", required = true)
            @RequestBody SysFiles sysFiles) {
        return success(this.sysFilesService.updateById(sysFiles));
    }

    @DeleteMapping
    @ApiOperation(value = "批量删除文件", notes = "根据文件ID列表批量删除文件，同时删除服务器上的物理文件")
    public AjaxResult delete(
            @ApiParam(value = "文件ID列表", required = true, example = "[1,2,3]")
            @RequestParam("idList") List<Long> idList) {
        try {
            // 先查询要删除的文件信息
            List<SysFiles> filesToDelete = this.sysFilesService.listByIds(idList);
            
            // 删除数据库记录
            boolean dbResult = this.sysFilesService.removeByIds(idList);
            
            if (dbResult) {
                // 数据库删除成功后，删除物理文件
                deletePhysicalFiles(filesToDelete);
                return success("文件删除成功");
            } else {
                return error("文件删除失败");
            }
        } catch (Exception e) {
            logger.error("批量删除文件失败，文件ID列表: {}, 错误信息: {}", idList, e.getMessage());
            return error("文件删除失败：" + e.getMessage());
        }
    }

    @DeleteMapping("/{id}")
    @ApiOperation(value = "删除单个文件", notes = "根据文件ID删除单个文件，同时删除服务器上的物理文件")
    public AjaxResult deleteById(
            @ApiParam(value = "文件ID", required = true, example = "1")
            @PathVariable Long id) {
        try {
            // 先查询要删除的文件信息
            SysFiles fileToDelete = this.sysFilesService.getById(id);
            if (fileToDelete == null) {
                return error("文件不存在");
            }
            
            // 删除数据库记录
            boolean dbResult = this.sysFilesService.removeById(id);
            
            if (dbResult) {
                // 数据库删除成功后，删除物理文件
                deletePhysicalFiles(Arrays.asList(fileToDelete));
                return success("文件删除成功");
            } else {
                return error("文件删除失败");
            }
        } catch (Exception e) {
            logger.error("删除文件失败，文件ID: {}, 错误信息: {}", id, e.getMessage());
            return error("文件删除失败：" + e.getMessage());
        }
    }

    @PostMapping("/upload")
    @ApiOperation(value = "文件上传", notes = "上传文件到服务器，支持单文件上传，自动生成存储路径和MD5校验")
    public AjaxResult uploadFile(
            @ApiParam(value = "上传的文件", required = true, example = "example.jpg")
            @RequestPart("file") MultipartFile file,

            @ApiParam(value = "父目录ID，用于文件分类管理", required = false)
            @RequestParam(value = "parentId", required = false) Long parentId) {
        try {
            // 验证文件
            if (file.isEmpty()) {
                return error("上传文件不能为空");
            }

            // 获取原始文件名和扩展名
            String originalFilename = file.getOriginalFilename();
            if (originalFilename == null || originalFilename.trim().isEmpty()) {
                return error("文件名不能为空");
            }

            String extension = "";
            int lastDotIndex = originalFilename.lastIndexOf(".");
            if (lastDotIndex > 0) {
                extension = originalFilename.substring(lastDotIndex + 1).toLowerCase();
            }

            // 生成存储文件名（UUID + 扩展名）
            String storageName = UUID.randomUUID().toString().replace("-", "");
            if (!extension.isEmpty()) {
                storageName += "." + extension;
            }

            // 创建上传目录（按日期分目录）
            String uploadPath1 = RuoYiConfig.getFilePath();
            String uploadDir = uploadPath1 + "/";
            String timePtah = LocalDate.now().toString();
            uploadDir = uploadDir + timePtah;
            Path uploadPath = Paths.get(uploadDir);
            if (!Files.exists(uploadPath)) {
                Files.createDirectories(uploadPath);
            }

            // 完整文件路径
            String filePath = uploadDir + "/" + storageName;
            Path targetPath = Paths.get(filePath);

            // 保存文件
            Files.copy(file.getInputStream(), targetPath);

            // 计算文件MD5
            String md5Hash = MD5Util.calculateMD5(file.getBytes());

            // 创建SysFiles对象
            SysFiles sysFiles = new SysFiles();
            sysFiles.setFileName(originalFilename);
            sysFiles.setStorageName(storageName);
            sysFiles.setFilePath("/profile/files/" + timePtah + "/" + storageName);
            sysFiles.setFileSize(file.getSize());
            sysFiles.setMimeType(file.getContentType());
            sysFiles.setExtension(extension);
            sysFiles.setMd5Hash(md5Hash);
            sysFiles.setUploadTime(new Date());
//            sysFiles.setUploadUserId(getUserId()); // 假设BaseController中有getUserId方法
            sysFiles.setLastModified(new Date());
            sysFiles.setVersion(1);
            sysFiles.setParentId(parentId);
            sysFiles.setIsDirectory(false);
            sysFiles.setStatus(1); // 1-正常状态

            // 保存到数据库
            boolean saved = this.sysFilesService.save(sysFiles);
            if (saved) {
                return success(sysFiles).put("msg", "文件上传成功");
            } else {
                // 如果数据库保存失败，删除已上传的文件
                Files.deleteIfExists(targetPath);
                return error("文件保存失败");
            }

        } catch (IOException e) {
            return error("文件上传失败：" + e.getMessage());
        } catch (Exception e) {
            return error("系统错误：" + e.getMessage());
        }
    }

    @GetMapping("/download/{id}")
    @ApiOperation(value = "文件下载", notes = "根据文件ID下载文件，支持断点续传和浏览器直接预览")
    public ResponseEntity<byte[]> downloadFile(
            @ApiParam(value = "文件ID", required = true, example = "1")
            @PathVariable Long id) {
        try {
            // 根据ID查询文件信息
            SysFiles sysFiles = this.sysFilesService.getById(id);
            if (sysFiles == null) {
                return ResponseEntity.notFound().build();
            }

            // 检查文件状态
            if (sysFiles.getStatus() != 1) {
                return ResponseEntity.badRequest().build();
            }

            // 将URL路径转换为物理文件路径
            String physicalPath = sysFiles.getFilePath().replace("/profile/", RuoYiConfig.getProfile() + "/");
            Path filePath = Paths.get(physicalPath);
            if (!Files.exists(filePath)) {
                return ResponseEntity.notFound().build();
            }

            // 读取文件内容
            byte[] fileContent = Files.readAllBytes(filePath);

            // 设置响应头
            HttpHeaders headers = new HttpHeaders();

            // 设置Content-Type
            String mimeType = sysFiles.getMimeType();
            if (mimeType == null || mimeType.isEmpty()) {
                mimeType = "application/octet-stream";
            }
            headers.setContentType(MediaType.parseMediaType(mimeType));

            // 设置Content-Disposition，支持中文文件名
            String fileName = sysFiles.getFileName();
            String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString())
                    .replaceAll("\\+", "%20");
            headers.setContentDispositionFormData("attachment", encodedFileName);

            // 设置文件大小
            headers.setContentLength(fileContent.length);

            // 设置缓存控制
            headers.setCacheControl("no-cache, no-store, must-revalidate");
            headers.setPragma("no-cache");
            headers.setExpires(0);

            return ResponseEntity.ok()
                    .headers(headers)
                    .body(fileContent);

        } catch (IOException e) {
            logger.error("文件下载失败，文件ID: {}, 错误信息: {}", id, e.getMessage());
            return ResponseEntity.internalServerError().build();
        } catch (Exception e) {
            logger.error("文件下载异常，文件ID: {}, 错误信息: {}", id, e.getMessage());
            return ResponseEntity.internalServerError().build();
        }
    }

    @GetMapping("/preview/{id}")
    @ApiOperation(value = "文件预览", notes = "根据文件ID预览文件，在浏览器中直接显示文件内容")
    public ResponseEntity<byte[]> previewFile(
            @ApiParam(value = "文件ID", required = true, example = "1")
            @PathVariable Long id) {
        try {
            // 根据ID查询文件信息
            SysFiles sysFiles = this.sysFilesService.getById(id);
            if (sysFiles == null) {
                return ResponseEntity.notFound().build();
            }

            // 检查文件状态
            if (sysFiles.getStatus() != 1) {
                return ResponseEntity.badRequest().build();
            }

            // 将URL路径转换为物理文件路径
            String physicalPath = sysFiles.getFilePath().replace("/profile/", RuoYiConfig.getProfile() + "/");
            Path filePath = Paths.get(physicalPath);
            if (!Files.exists(filePath)) {
                return ResponseEntity.notFound().build();
            }

            // 读取文件内容
            byte[] fileContent = Files.readAllBytes(filePath);

            // 设置响应头
            HttpHeaders headers = new HttpHeaders();

            // 设置Content-Type
            String mimeType = sysFiles.getMimeType();
            if (mimeType == null || mimeType.isEmpty()) {
                mimeType = "application/octet-stream";
            }
            headers.setContentType(MediaType.parseMediaType(mimeType));

            // 设置Content-Disposition为inline，让浏览器直接显示
            headers.setContentDispositionFormData("inline", sysFiles.getFileName());

            // 设置文件大小
            headers.setContentLength(fileContent.length);

            return ResponseEntity.ok()
                    .headers(headers)
                    .body(fileContent);

        } catch (IOException e) {
            logger.error("文件预览失败，文件ID: {}, 错误信息: {}", id, e.getMessage());
            return ResponseEntity.internalServerError().build();
        } catch (Exception e) {
            logger.error("文件预览异常，文件ID: {}, 错误信息: {}", id, e.getMessage());
            return ResponseEntity.internalServerError().build();
        }
    }

    /**
     * 删除物理文件
     */
    private void deletePhysicalFiles(List<SysFiles> files) {
        for (SysFiles file : files) {
            try {
                // 将URL路径转换为物理文件路径
                String physicalPath = file.getFilePath().replace("/profile/", RuoYiConfig.getProfile() + "/");
                Path filePath = Paths.get(physicalPath);

                if (Files.exists(filePath)) {
                    Files.delete(filePath);
                    logger.info("物理文件删除成功: {}", physicalPath);

                    // 检查并删除空目录
                   FileUtils.deleteEmptyDirectories(filePath.getParent());
                } else {
                    logger.warn("物理文件不存在，跳过删除: {}", physicalPath);
                }
            } catch (IOException e) {
                logger.error("删除物理文件失败: {}, 错误信息: {}", file.getFilePath(), e.getMessage());
            }
        }
    }

}
